1) Interpreted with REPL.
Makes for a rather boring "hello world!"
:
>>> 'hello.'
But great for experimenting:
>>> dir('hello.')'upper' looks interesting ...
>>> dir('hello'.upper)Maybe '__doc__' will help ...
>>> print 'hello'.upper.__doc__ ... >>> 'hello'.upper()OK, so we cheated a bit: had to know about
dir()
and
print
. How would we learn more about
dir
(and why won't that work for print
)?
Worth noting:
>>> dir(1) ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__str__', '__sub__', '__truediv__', '__xor__'] >>>Unfortunately, syntax rules get in the way of
1.__doc__
But, we can still do things like >>> (1).__add__(2) 3In a concession to the brevity of life, we can also, of course, write:
>>> 1 + 2 3
All the usual types are available: booleans, integers, reals, strings; with dynamic typing:
>>> x = 'three' >>> x = 3Integers are “infinite”:
>>> for shift in range(100): print shift, 1 << shiftso don't count on wrap-around behavior.
There is no byte/character type, just a one element string.
for
loops are available, with break
and continue
. for
may also have an else
(executed if the loop is not broken). The if
, elif
, else
construct is also present, but not 'switch' or 'while'.
Statement groups within the body of a for
loop or an if
branch are set off by indention, even in the REPL:
>>> for x in ['cat', 'dog', 'mouse']: ... if x.upper() == 'DOG': File "", line 2 if x.upper() == 'DOG': ^ IndentationError: expected an indented block >>> for x in ['cat', 'dog', 'mouse']: ... if x.upper() == 'DOG': ... print x + ' grew up to be a big dog!' File " ", line 3 print x + ' grew up to be a big dog!' ^ IndentationError: expected an indented block >>> for x in ['cat', 'dog', 'mouse']: ... if x.upper() == 'DOG': ... print x + ' grew up to be a big dog!' ... dog grew up to be a big dog!
List are fairly self-evident: they impose an ordering on a heterogeneous collection of objects, including other lists. A given element of a list may be referenced via it's 0-based index, and list objects support a number of methods (as usual, try dir
).
>>> l = ['a', 2, [3.4, 5.6]] >>> l[0] 'a' >>> l[-1] [3.3999999999999999, 5.5999999999999996] >>> len(l) 3 >>> l[:2] ['a', 2] >>> l[::-1] [[3.3999999999999999, 5.5999999999999996], 2, 'a'] >>> l.append('moo') >>> l ['a', 2, [3.3999999999999999, 5.5999999999999996], 'moo'] >>> l[2][1] 5.5999999999999996 >>> l.pop(2) [3.3999999999999999, 5.5999999999999996] >>> l ['a', 2, 'moo'] >>> ll = l + l >>> ll ['a', 2, 'moo', 'a', 2, 'moo']Tuples are akin to lists, but are immutable and are constructed using
( )
.
>>> t = ('a', 2, 'moo') >>> l ['a', 2, 'moo'] >>> t ('a', 2, 'moo') >>> l[1] = 'cow' >>> l ['a', 'cow', 'moo'] >>> t[1] = 'cow' Traceback (most recent call last): File "Dictionaries are extremely useful mapping containers:", line 1, in TypeError: 'tuple' object does not support item assignment
>>> d = {'perl': 'good', 'ruby': 'better', 'python': 'best'} >>> d['python'] 'best' >>> for k in d: print k, d[k] ... python best ruby better perl good >>> len(d) 3 >>> for k in ['ada', 'python', 'tex']: print k, d.get(k, '???') ... ada ??? python best tex ???You can dynamically add new keys to the dictionary:
>>> rolls = {} >>> for x in range(10): rolls[randint(1,6)] = 1 ... >>> rolls {1: 1, 2: 1, 3: 1, 5: 1, 6: 1}And easily test for the presence of a key:
>>> [ x for x in range(1,7) if x not in rolls ] [4]Interesting list construction, no? A list comprehension. “One liner” for loops, and then some: conditionally apply processing to the elements of nested lists of sequences.
>>> powers = [[x**y for y in range(0, 5)] for x in range(0, 101)] >>> powers[2][4] 16A little more complex:
>>> factors = [[y for y in range(1,x) if x and not x%y ] for x in range(1000)] >>> [x for x in range(1000) if x == sum(factors[x])]
Basics:
def factorial(n): if n == 0: return 1 else: return n*factorial(n-1)As usual, code blocks are set off by indentation. And, as usual, functions are objects:
>>> dir(factorial) ['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] >>> dir(factorial.func_code) ['__class__', '__cmp__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']Power users can have a field day with these.
No return required:
def hw(): print 'hola.' >>> print hw() hola. NoneBut many values allowed:
def mv(): return 1, 2.3, 'hi' >>> r = mv() >>> r (1, 2.2999999999999998, 'hi') >>> r0, r1, r2 = mv() >>> print r0, r1, r2 1 2.3 hiAnd what about that nifty
__doc__
stuff?
def hw(): 'You say goodbye and I say hello' return 'hello' >>> hw() 'hello' >>> print hw.__doc__ You say goodbye and I say hello
An argument list can have a fairly complex structure:
def args(a, *b, **c): print 'a: ', a print 'b: ', b print 'c: ', c >>> args(123, 4, 5, 6, cat='dog') 123 (4, 5, 6) {'cat': 'dog'}Possible to have positional, variadic and “keyword” arguments. Positionals can be named and have defaults. We'll only comment on a few features here, see the usual references for details.
Named arguments are useful for “simulating” polymorphism:
def pt(x=0, y=0): return (x, y) >>> pt() (0, 0) >>>pt(1) (1, 0) >>> pt(y=2) (0, 2) >>> pt(x=2) (2, 0) >>> pt(3, 4) (3, 4) >>>The
*
and **
syntax can also be used for invocations:
>>> t = (111, 222) >>> pt(t) ((111, 222), 0) >>> pt(*t) (111, 222) >>> d = {'y': -1, 'x': 1} >>> pt(d) ({'y': -1, 'x': 1}, 0) >>> pt(*d) ('y', 'x') >>> pt(**d) (1, -1)For you Haskell/ML fans:
def tx(x): def f(n): return x*n return f >>> t3 = tx(3) >>> t13 = tx(13) >>> t3(11) 33 >>> t13(11) 143Now that we are dealing with larger amounts of code, we should note that python can be invoked with a script file on the command line, in which case the commands executed are taken from the script. (One can also use
#!/usr/bin/env python
as the first line and chmod
the script to make it directly executable.)
raise
, try
, and except
.
def grouchy(x): raise Exception('I don\'t like %s!'%repr(x)) >>> grouchy(3) Traceback (most recent call last): File "By default, an exception generates a trace back, an Exception description and returns control to the interpreter or exits a script. This behavior can be changed by the use of", line 1, in File " ", line 1, in grouchy Exception: I don't like 3!
try
– except
:
>>> for x in ['peas', 'carrots']: ... try: grouchy(x) ... except Exception, e: print e ... else: print 'all done' ... I don't like 'peas'! I don't like 'carrots'! all done >>> for x in ['peas', 'carrots']: grouchy(x) ... Traceback (most recent call last): File "A full block of code can follow the", line 1, in File " ", line 1, in grouchy Exception: I don't like 'peas'!
:
. If not altered by the except
code block, control will flow to the next statement after the try
– except
when an exception is “caught”.
Exceptions are the general mechanism used by Python for almost all problems:
>>> 1/0 Traceback (most recent call last): File "", line 1, in ZeroDivisionError: integer division or modulo by zero >>> open('NoFile') Traceback (most recent call last): File " ", line 1, in IOError: [Errno 2] No such file or directory: 'NoFile' >>>
except
can be targeted (as well as nested and chained):
>>> try: open('NoFile') ... except IOError: 'no biggie.' ... 'no biggie.' >>> try: 1/0 ... except IOError: 'no biggie.' ... Traceback (most recent call last): File "This mechanism, of course, can be used for general flow control — not just exceptional events.", line 1, in ZeroDivisionError: integer division or modulo by zero
def boredP(x, depth=0): if depth > 13: raise Exception('I\'m bored!') if x: boredP(x-1, depth+1) >>> try: boredP(3) ... except: 'got bored' ... >>> try: boredP(33) ... except: 'got bored' ... 'got bored'Note: because exceptions are so general, using untargeted
except
s may be a bad idea in that they can mask important problems.
break
, next
, step
, where
, etc. Type help
when in the debugger for a full list. Anything not recognized as a debugger command is assumed to be a normal Python statement and is executed in the current context.
>>> import pdb >>> pdb.runcall(ff, 7) > /home/carriero/python/cs424/intro2/ff.py(2)ff() -> if 0 == n: return 1 (Pdb) step > /home/carriero/python/cs424/intro2/ff.py(3)ff() -> return n*ff(n-1) (Pdb) --Call-- > /home/carriero/python/cs424/intro2/ff.py(1)ff() -> def ff(n): (Pdb) > /home/carriero/python/cs424/intro2/ff.py(2)ff() -> if 0 == n: return 1 (Pdb) > /home/carriero/python/cs424/intro2/ff.py(3)ff() -> return n*ff(n-1) (Pdb) --Call-- > /home/carriero/python/cs424/intro2/ff.py(1)ff() -> def ff(n): (Pdb) where /home/carriero/myInstalls/lib/python2.5/bdb.py(404)runcall() -> res = func(*args, **kwds) /home/carriero/python/cs424/intro2/ff.py(3)ff() -> return n*ff(n-1) /home/carriero/python/cs424/intro2/ff.py(3)ff() -> return n*ff(n-1) > /home/carriero/python/cs424/intro2/ff.py(1)ff() -> def ff(n): (Pdb) print n 5 (Pdb) return --Return-- > /home/carriero/python/cs424/intro2/ff.py(3)ff()->120 -> return n*ff(n-1) (Pdb) --Return-- > /home/carriero/python/cs424/intro2/ff.py(3)ff()->720 -> return n*ff(n-1) (Pdb) return --Return-- > /home/carriero/python/cs424/intro2/ff.py(3)ff()->5040 -> return n*ff(n-1) (Pdb) 5040 >>>The debugger may be run, as just shown, within an interactive session, or it may be used to run a script file. In the latter case (or in an interactive session but when debugging code read from a file, say with
import
or execfile
), the debugger plays nicely with emacs.
It is worth investing a little time becoming comfortable with the debugger. The pdb module documentation at the Python web site is good, but no substitute for some hands-on experimenting.
One way to think of a Python class instance is as a kind of container:
>>> class Struct: pass ... >>> s = Struct() >>> s.a = 1 >>> s.b = 2.3 >>> s.c = ['a', 'b', 'c'] >>> s <__main__.Struct instance at 0xb7c707ac> >>> dir(s) ['__doc__', '__module__', 'a', 'b', 'c'] >>> s.b 2.2999999999999998 >>>By convention, interesting things happen with certain bits of the contents:
class C: 'C is for "container".' def __init__(self, forMe=None): print 'Instantiating a C' if forMe: self.forMe = forMe >>> C.__doc__ 'C is for "container".' >>> c0 = C() Instantiating a C >>> c0.__doc__ 'C is for "container".' >>> dir(c0) ['__doc__', '__init__', '__module__']But the instance is still a container ...
>>> c0.foo = 123 >>> dir(c0) ['__doc__', '__init__', '__module__', 'foo'] >>> c0.foo 123 >>> c1 = C('hi') Instantiating a C >>> dir(c1) ['__doc__', '__init__', '__module__', 'forMe'] >>> c1.forMe 'hi' >>> c1.foo = 321 >>> dir(c1) ['__doc__', '__init__', '__module__', 'foo', 'forMe'] >>> c1.foo 321It should be clear that
__init__
is a bit of “special” content that corresponds to a constructor. There are others:
class C: 'C is for "container".' def __init__(self, forMe=None): print 'Instantiating a C' if forMe: self.mine = forMe def __str__(self): try: return repr(self.mine) + ' is all mine.' except: return 'I\'m empty' def __getitem__(self, tag): return 'I sure wish I had a '+repr(tag) def __setitem__(self, tag, val): print 'No room for a %s in the %s box'%(repr(val), repr(tag))
>>> c0 = C() Instantiating a C >>> c1 = C('Foo') Instantiating a C >>> print c0 I'm empty >>> print c1 'Foo' is all mine. >>> c1[3] = 'cat' No room for a 'cat' in the 3 box >>> c1[3] 'I sure wish I had a 3'A more traditional example:
class S: 'S is for "stack".' def __init__(self, data=[]): self.data = data[::] # = data would be a mistake. def push(self, v): self.data.append(v) def pop(self): return self.data.pop(-1) def __iter__(self): class x: def __init__(self, l): self.l = l[::] def next(self): if not self.l: raise StopIteration return self.l.pop(0) return x(self.data) >>> s = S() >>> s.push('cat') >>> s.push('mouse') >>> s.push('dog') >>> for x in s: ... for y in s: print x, y ... cat cat cat mouse cat dog mouse cat mouse mouse mouse dog dog cat dog mouse dog dogSubclassing, of course, is also “in there”:
from random import randint class RS(S): 'R is for "random".' def __init__(self, data=[]): S.__init__(self, data) def push(self, v): self.data.insert(randint(0, len(self.data)), v) >>> s = S() >>> r = RS() >>> for x in xrange(13): ... s.push(x) ... r.push(x) ...So much for encpasulation:
>>> s.data [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] >>> r.data [8, 9, 10, 7, 4, 5, 0, 6, 12, 11, 2, 3, 1]The class RS does inherit the iterator and the pop method:
>>> [x for x in r] [8, 9, 10, 7, 4, 5, 0, 6, 12, 11, 2, 3, 1] >>> r.pop() 1
os
and sys
.
>>> import sys >>> sys.version '2.5 (r25:51908, Nov 20 2006, 21:33:12) \n[GCC 4.1.1 20061011 (Red Hat 4.1.1-30)]' >>> sys.argv [''] >>> sys.stdout.write('hola.') hola.>>> sys.stdout.write('hola.\n') hola.
import
is not the only way to access a module.
>>> from os import getcwd, popen as pOp >>> getcwd() '/home/carriero/python/cs424/intro2' >>> for l in pOp('ls *py'): print l[:-1] ... ff.py menu.pyIf you are developing a module, note that you can
reload
, but this does not always do what you want — you may want to use execfile
during the main debugging phase.
Also see the module imp
.
And that's just the beginning... .
The History of every major Galactic Civilization tends to pass through three distinct and recognizable phases, those of Survival, Inquiry and Sophistication, otherwise known as the How, Why and Where phases. For instance, the first phase is characterized by the question ''How can we eat?'', the second by the question ''Why do we eat?'' and the third by the question, ''Where shall we have lunch?''We can advance the cause of civilization in 42 lines of code.
One good book (there are many): David Beazley, Python Essential Reference, New Riders.